Model Deployment : Exploring Modular Application Programming Interface Frameworks For Serving Model Predictions¶


John Pauline Pineda

February 8, 2025


  • 1. Table of Contents
    • 1.1 Project Background
      • 1.1.1 Categorical Classification
        • 1.1.1.1 Data Background
        • 1.1.1.2 Model Background
        • 1.1.1.3 Deployment Background
      • 1.1.2 Survival Prediction
        • 1.1.2.1 Data Background
        • 1.1.2.2 Model Background
        • 1.1.2.3 Deployment Background
      • 1.1.3 Survival Prediction
        • 1.1.3.1 Data Background
        • 1.1.3.2 Model Background
        • 1.1.3.3 Deployment Background
    • 1.2 Application Programming Interface (API) Development Using the FastAPI Framework
      • 1.2.1 Categorical Classification
        • 1.2.1.1 API Building
        • 1.2.1.2 API Testing
      • 1.2.2 Categorical Classification
        • 1.2.2.1 API Building
        • 1.2.2.2 API Testing
      • 1.2.3 Categorical Classification
        • 1.2.3.1 API Building
        • 1.2.3.2 API Testing
    • 1.3 Application Programming Interface (API) Development Using the Flask Framework
      • 1.3.1 Categorical Classification
        • 1.3.1.1 API Building
        • 1.3.1.2 API Testing
      • 1.3.2 Categorical Classification
        • 1.3.2.1 API Building
        • 1.3.2.2 API Testing
      • 1.3.3 Categorical Classification
        • 1.3.3.1 API Building
        • 1.3.3.2 API Testing
    • 1.4 Consolidated Findings
  • 2. Summary
  • 3. References

1. Table of Contents ¶

1.1. Project Background ¶

1.1.1 Categorical Classification ¶

1.1.1.1 Data Background ¶

cc_data_background.png

1.1.1.2 Model Background ¶

cc_model_background.png

1.1.1.3 Deployment Background ¶

cc_deployment_background.png

1.1.2 Survival Prediction ¶

1.1.2.1 Data Background ¶

sp_data_background.png

1.1.2.2 Model Background ¶

sp_model_background.png

1.1.2.3 Deployment Background ¶

sp_deployment_background.png

1.1.3 Image Classification ¶

1.1.3.1 Data Background ¶

ic_data_background.png

1.1.3.2 Model Background ¶

ic_model_background.png

1.1.3.3 Deployment Background ¶

ic_deployment_background.png

1.2. Application Programming Interface (API) Development Using the FastAPI Framework ¶

1.2.1 Categorical Classification ¶

1.2.1.1 API Building ¶

cc_fastapi_code.png

1.2.1.2 API Testing ¶

cc_fastapi_activation.png

cc_fastapi_documentation.png

cc_fastapi_endpoints.png

In [1]:
##################################
# Loading Python Libraries
##################################
import requests
In [2]:
##################################
# Defining the base URL of the API
# for the categorical classification model
##################################
CC_FASTAPI_BASE_URL = "http://127.0.0.1:8000"
In [3]:
##################################
# Defining the input values for an individual test case
##################################
individual_test_case = {
    "features_individual": [1, 0, 0, 0, 0, 1, 0, 0, 1, 1] 
}
In [4]:
##################################
# Defining the input values for a batch of cases
##################################
batch_test_case = {
    "features_list": [
        [1, 0, 0, 0, 0, 1, 0, 0, 1, 1], 
        [1, 0, 1, 0, 1, 1, 0, 1, 1, 1]
    ]
}
In [5]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{CC_FASTAPI_BASE_URL}/")
if response.status_code == 200:
    print("Root Endpoint Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Root Endpoint Response: {'message': 'Welcome to the Categorical Classification API!'}
In [6]:
##################################
# Generating a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{CC_FASTAPI_BASE_URL}/predict-individual-logit-probability-class", json=individual_test_case)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'logit': -1.2117837409390746,
 'probability': 0.22938559072691203,
 'risk_class': 'Low-Risk'}
In [7]:
##################################
# Sending a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of a list of train cases
##################################
response = requests.post(f"{CC_FASTAPI_BASE_URL}/predict-list-logit-probability-class", json=batch_test_case)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'logit': [-1.2117837409390746, 3.4784950973590973],
 'probability': [0.22938559072691203, 0.9700696569701589],
 'logit_sorted': [-1.2117837409390746, 3.4784950973590973],
 'probability_sorted': [0.22938559072691203, 0.9700696569701589]}
In [8]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [1, 0, 1]}
response = requests.post(f"{CC_FASTAPI_BASE_URL}/predict-individual-logit-probability-class", json=malformed_test_case)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Error: 422 {"detail":[{"type":"missing","loc":["body","features_individual"],"msg":"Field required","input":{"features":[1,0,1]}}]}

1.2.2 Survival Prediction ¶

1.2.2.1 API Building ¶

sp_fastapi_code.png

1.2.2.2 API Testing ¶

sp_fastapi_activation.png

sp_fastapi_documentation.png

sp_fastapi_endpoints.png

In [9]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import pandas as pd
import base64
from IPython.display import display
from PIL import Image
In [10]:
##################################
# Defining the base URL of the API
# for the survival prediction model
##################################
SP_FASTAPI_BASE_URL = "http://127.0.0.1:8001"
In [11]:
##################################
# Defining the input values for an individual test case
##################################
single_test_case = {
    "features_individual": [43, 0, 75, 1, 0.75, 100]  
}
In [12]:
##################################
# Defining the input values for a batch of cases
##################################
train_list = {
        "features_list": [
            [43, 0, 75, 1, 0.75, 100],
            [70, 1,	20,	1, 0.75, 100]
        ]
    }
In [13]:
##################################
# Defining the input values for a batch of cases for binning request
##################################
bin_request = {
        "X_original_list": [
            {"AGE": -0.10, "EJECTION_FRACTION": -0.10, "SERUM_CREATININE ": -0.10, "SERUM_SODIUM": -0.10},
            {"AGE": 0.20, "EJECTION_FRACTION": 0.20, "SERUM_CREATININE ": 0.20, "SERUM_SODIUM": 0.20},
            {"AGE": 0.90, "EJECTION_FRACTION": 0.90, "SERUM_CREATININE ": 0.90, "SERUM_SODIUM": 0.90}
        ],
        "numeric_feature": "AGE"
    }
In [14]:
##################################
# Defining the input values for a batch of cases for Kaplan-Meier plotting
##################################
km_request = {
        "df": [
            {"TIME": 0, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 25, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 50, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 100, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 125, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 150, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 175, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 200, "DEATH_EVENT": 0, "AGE": "Low"},
            {"TIME": 225, "DEATH_EVENT": 1, "AGE": "Low"},
            {"TIME": 250, "DEATH_EVENT": 1, "AGE": "Low"},
            {"TIME": 0, "DEATH_EVENT": 0, "AGE": "High"},
            {"TIME": 25, "DEATH_EVENT": 0, "AGE": "High"},
            {"TIME": 50, "DEATH_EVENT": 0, "AGE": "High"},
            {"TIME": 100, "DEATH_EVENT": 1, "AGE": "High"},
            {"TIME": 125, "DEATH_EVENT": 0, "AGE": "High"},
            {"TIME": 150, "DEATH_EVENT": 0, "AGE": "High"},
            {"TIME": 175, "DEATH_EVENT": 1, "AGE": "High"},
            {"TIME": 200, "DEATH_EVENT": 1, "AGE": "High"},
            {"TIME": 225, "DEATH_EVENT": 1, "AGE": "High"},
            {"TIME": 250, "DEATH_EVENT": 1, "AGE": "High"},
        ],
        "cat_var": "AGE",
        "new_case_value": "Low"
    }
In [15]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{SP_FASTAPI_BASE_URL}/")
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
'Response:'
{'message': 'Welcome to the Survival Prediction API!'}
In [16]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile,
# estimating the heart failure survival probabilities,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/compute-individual-coxph-survival-probability-class/", json=single_test_case)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'survival_function': [0.9973812917524568,
  0.9920416812438736,
  0.9893236791425079,
  0.972381113071464,
  0.9693179903073035,
  0.9631930672135339,
  0.9631930672135339,
  0.9600469571766689,
  0.9600469571766689,
  0.9568596864927983,
  0.9536305709158891,
  0.9471625843882805,
  0.93729581350105,
  0.9338986486591409,
  0.93048646553474,
  0.9270645831787163,
  0.9202445006124622,
  0.9167715111530355,
  0.9132845175345189,
  0.9097550958520674,
  0.9097550958520674,
  0.9097550958520674,
  0.9060810720432387,
  0.9024157452999795,
  0.9024157452999795,
  0.9024157452999795,
  0.9024157452999795,
  0.9024157452999795,
  0.8985598696587259,
  0.8985598696587259,
  0.8985598696587259,
  0.8945287485160898,
  0.8945287485160898,
  0.8945287485160898,
  0.8945287485160898,
  0.8901959645503091,
  0.8812352215018253,
  0.8812352215018253,
  0.8812352215018253,
  0.8812352215018253,
  0.8764677174183527,
  0.8764677174183527,
  0.8764677174183527,
  0.8764677174183527,
  0.8709113650481243,
  0.8709113650481243,
  0.8652494086650531,
  0.8593884303802698,
  0.8593884303802698,
  0.8593884303802698,
  0.8593884303802698,
  0.8593884303802698,
  0.8528574859874233,
  0.8528574859874233,
  0.8528574859874233,
  0.8528574859874233,
  0.8528574859874233,
  0.8459534502216807,
  0.8389821875092403,
  0.8319419786276306,
  0.8246669811915435,
  0.8099879066057215,
  0.8099879066057215,
  0.7943979200335176,
  0.7943979200335176,
  0.7943979200335176,
  0.7943979200335176,
  0.7943979200335176,
  0.7848178617845467,
  0.7848178617845467,
  0.7848178617845467,
  0.7848178617845467,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7555469848652164,
  0.7555469848652164,
  0.7555469848652164,
  0.7555469848652164,
  0.7555469848652164,
  0.7337716342207724,
  0.7337716342207724,
  0.7337716342207724,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696],
 'survival_time': [50, 100, 150, 200, 250],
 'survival_probabilities': [90.97550958520674,
  87.64677174183527,
  84.59534502216806,
  78.48178617845467,
  70.70184115456696],
 'risk_category': 'Low-Risk'}
In [17]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile and
# estimating the heart failure survival probabilities
# of a list of train cases
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/compute-list-coxph-survival-profile/", json=train_list)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'survival_profiles': [[0.9973812917524568,
   0.9920416812438736,
   0.9893236791425079,
   0.972381113071464,
   0.9693179903073035,
   0.9631930672135339,
   0.9631930672135339,
   0.9600469571766689,
   0.9600469571766689,
   0.9568596864927983,
   0.9536305709158891,
   0.9471625843882805,
   0.93729581350105,
   0.9338986486591409,
   0.93048646553474,
   0.9270645831787163,
   0.9202445006124622,
   0.9167715111530355,
   0.9132845175345189,
   0.9097550958520674,
   0.9097550958520674,
   0.9097550958520674,
   0.9060810720432387,
   0.9024157452999795,
   0.9024157452999795,
   0.9024157452999795,
   0.9024157452999795,
   0.9024157452999795,
   0.8985598696587259,
   0.8985598696587259,
   0.8985598696587259,
   0.8945287485160898,
   0.8945287485160898,
   0.8945287485160898,
   0.8945287485160898,
   0.8901959645503091,
   0.8812352215018253,
   0.8812352215018253,
   0.8812352215018253,
   0.8812352215018253,
   0.8764677174183526,
   0.8764677174183526,
   0.8764677174183526,
   0.8764677174183526,
   0.8709113650481243,
   0.8709113650481243,
   0.8652494086650531,
   0.8593884303802697,
   0.8593884303802697,
   0.8593884303802697,
   0.8593884303802697,
   0.8593884303802697,
   0.8528574859874233,
   0.8528574859874233,
   0.8528574859874233,
   0.8528574859874233,
   0.8528574859874233,
   0.8459534502216807,
   0.8389821875092403,
   0.8319419786276306,
   0.8246669811915435,
   0.8099879066057215,
   0.8099879066057215,
   0.7943979200335176,
   0.7943979200335176,
   0.7943979200335176,
   0.7943979200335176,
   0.7943979200335176,
   0.7848178617845467,
   0.7848178617845467,
   0.7848178617845467,
   0.7848178617845467,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7555469848652164,
   0.7555469848652164,
   0.7555469848652164,
   0.7555469848652164,
   0.7555469848652164,
   0.7337716342207724,
   0.7337716342207724,
   0.7337716342207724,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695],
  [0.9761144218801228,
   0.928980888267716,
   0.905777064852962,
   0.7724242339590301,
   0.7502787164583535,
   0.7076872741961866,
   0.7076872741961866,
   0.6866593185026403,
   0.6866593185026403,
   0.6659260634219393,
   0.6454915885099762,
   0.6062342264686207,
   0.5504405490863784,
   0.5323184765768243,
   0.5146536440658629,
   0.49746533888245986,
   0.464726413395405,
   0.4488047347163327,
   0.433309930422515,
   0.4181140392975694,
   0.4181140392975694,
   0.4181140392975694,
   0.4028020116306455,
   0.38802639234746467,
   0.38802639234746467,
   0.38802639234746467,
   0.38802639234746467,
   0.38802639234746467,
   0.373006008573048,
   0.373006008573048,
   0.373006008573048,
   0.35785929480690143,
   0.35785929480690143,
   0.35785929480690143,
   0.35785929480690143,
   0.3421927616040032,
   0.3117176431598899,
   0.3117176431598899,
   0.3117176431598899,
   0.3117176431598899,
   0.29651072362871467,
   0.29651072362871467,
   0.29651072362871467,
   0.29651072362871467,
   0.2796248763802668,
   0.2796248763802668,
   0.2633052706162029,
   0.24731169874453887,
   0.24731169874453887,
   0.24731169874453887,
   0.24731169874453887,
   0.24731169874453887,
   0.23051507888001282,
   0.23051507888001282,
   0.23051507888001282,
   0.23051507888001282,
   0.23051507888001282,
   0.213871875082776,
   0.19816204676152543,
   0.18334919195124752,
   0.16908728217620728,
   0.1432835564355214,
   0.1432835564355214,
   0.119778195679268,
   0.119778195679268,
   0.119778195679268,
   0.119778195679268,
   0.119778195679268,
   0.10710184631976834,
   0.10710184631976834,
   0.10710184631976834,
   0.10710184631976834,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.07544024472233593,
   0.07544024472233593,
   0.07544024472233593,
   0.07544024472233593,
   0.07544024472233593,
   0.05761125190131533,
   0.05761125190131533,
   0.05761125190131533,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404]]}
In [18]:
##################################
# Sending a POST endpoint request for
# creating dichotomous bins for the numeric features
# of a list of train cases
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/bin-numeric-model-feature/", json=bin_request)
if response.status_code == 200:
    display("Response:", pd.DataFrame(response.json()))
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
AGE EJECTION_FRACTION SERUM_CREATININE SERUM_SODIUM
0 Low -0.1 -0.1 -0.1
1 High 0.2 0.2 0.2
2 High 0.9 0.9 0.9
In [19]:
##################################
# Sending a POST endpoint request for
# plotting the estimated survival profiles
# using Kaplan-Meier Plots
##################################
response = requests.post(f"{SP_FASTAPI_BASE_URL}/plot-kaplan-meier/", json=km_request)
if response.status_code == 200:
    plot_data = response.json()["plot"]
    # Decoding and displaying the plot
    img = base64.b64decode(plot_data)
    with open("kaplan_meier_plot.png", "wb") as f:
        f.write(img)
        display(Image.open("kaplan_meier_plot.png"))
else:
    print("Error:", response.status_code, response.text)
    
No description has been provided for this image
In [20]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [43, 0, 75, 1, 0.75]}
response = requests.post(f"{SP_FASTAPI_BASE_URL}/compute-individual-coxph-survival-probability-class", json=malformed_test_case)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Error: 422 {"detail":[{"type":"missing","loc":["body","features_individual"],"msg":"Field required","input":{"features":[43,0,75,1,0.75]}}]}

1.2.3 Image Classification ¶

1.2.3.1 API Building ¶

ic_fastapi_code.png

1.2.3.2 API Testing ¶

ic_fastapi_activation.png

ic_fastapi_documentation.png

ic_fastapi_endpoints.png

In [21]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import base64
from IPython.display import display
from PIL import Image
import matplotlib.pyplot as plt
import io
from tensorflow.keras.utils import load_img
import os
import mimetypes
In [22]:
##################################
# Defining the base URL of the API
# for the image classification model
##################################
IC_FASTAPI_BASE_URL = "http://127.0.0.1:8002"
In [23]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
image_path = (os.path.join("..",IMAGES_PATH, "test_image.jpg"))
In [24]:
##################################
# Automatically determining the filename and content type
##################################
image_path_filename = os.path.basename(image_path)
image_path_content_type, _ = mimetypes.guess_type(image_path)
In [25]:
##################################
# Visualizing the individual test image
##################################
try:
    image = Image.open(image_path)
    print(f"Image File Path: {image_path}")
    print(f"Image Format: {image.format}")
    print(f"Image Size: {image.size}")
    print(f"Image Mode: {image.mode}") 
except Exception as e:
    print(f"Error loading image: {e}")
plt.imshow(image)
plt.axis('off') 
plt.title("Test Image")
plt.show()
Image File Path: ..\image_classification_study\images\test_image.jpg
Image Format: JPEG
Image Size: (215, 234)
Image Mode: RGB
No description has been provided for this image
In [26]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{IC_FASTAPI_BASE_URL}/")
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'message': 'Welcome to the Image Classification API!'}
In [27]:
##################################
# Sending a POST endpoint request for
# ensuring that the file upload mechanism is working
# by returning the the file metadata
##################################
with open(image_path, "rb") as file:
    files = {"file": (image_path_filename, file, image_path_content_type)}
    response = requests.post(f"{IC_FASTAPI_BASE_URL}/test-file-upload/", files=files)

    if response.status_code == 200:
        result = response.json()
        print("File Upload Test Result:")
        print(f"Filename: {result['filename']}")
        print(f"Content Type: {result['content_type']}")
        print(f"Size: {result['size']} bytes")
    else:
        print(f"Error: {response.status_code} - {response.text}")
        
File Upload Test Result:
Filename: test_image.jpg
Content Type: image/jpeg
Size: 12103 bytes
In [28]:
##################################
# Sending a POST endpoint request for
# predicting the image category and
# estimating class probabilities
# of an individual test image
##################################
with open(image_path, "rb") as file:
    files = {"file": ("image.jpg", file, "image/jpeg")}
    response = requests.post(f"{IC_FASTAPI_BASE_URL}/predict-image-category-class-probability/", files=files)
    
    if response.status_code == 200:
        result = response.json()
        print("Prediction Result:")
        print(f"Predicted Class: {result['predicted_class']}")
        print("Probabilities:")
        for cls, prob in result["probabilities"].items():
            print(f"{cls}: {prob:.5f}%")
    else:
        print(f"Error: {response.status_code} - {response.text}")
            
Prediction Result:
Predicted Class: Meningioma
Probabilities:
No Tumor: 12.94989%
Glioma: 0.02788%
Meningioma: 87.02222%
Pituitary: 0.00002%
In [29]:
##################################
# Sending a POST endpoint request for
# formulating the gradient class activation map
# from the output of the first to third convolutional layers and
# and superimposing on the actual image
##################################
with open(image_path, "rb") as file:
    files = {"file": ("image.jpg", file, "image/jpeg")}
    response = requests.post(f"{IC_FASTAPI_BASE_URL}/visualize-image-gradcam/", files=files)
    
    if response.status_code == 200:
        plot_data = response.json()["plot"]
        # Decoding and displaying the plot
        img = base64.b64decode(plot_data)
        with open("image_gradcam_plot.png", "wb") as f:
            f.write(img)
            display(Image.open("image_gradcam_plot.png"))
    else:
        print(f"Error: {response.status_code} - {response.text}")
        
No description has been provided for this image
In [30]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
malformed_image_path = (os.path.join("..",IMAGES_PATH, "test_image.png"))
In [31]:
##################################
# Automatically determining the filename and content type
##################################
malformed_image_path_filename = os.path.basename(image_path)
malformed_image_path_content_type, _ = mimetypes.guess_type(malformed_image_path)
In [32]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
with open(malformed_image_path, "rb") as file:
    files = {"file": (malformed_image_path_filename, file, malformed_image_path_content_type)}
    response = requests.post(f"{IC_FASTAPI_BASE_URL}/test-file-upload/", files=files)

    if response.status_code == 200:
        result = response.json()
        print("File Upload Test Result:")
        print(f"Filename: {result['filename']}")
        print(f"Content Type: {result['content_type']}")
        print(f"Size: {result['size']} bytes")
    else:
        print(f"Error: {response.status_code} - {response.text}")
        
Error: 400 - {"detail":"File must be a JPEG image"}

1.3. Application Programming Interface (API) Development Using the Flask Framework ¶

1.3.1 Categorical Classification ¶

1.3.1.1 API Building ¶

cc_flaskapi_code.png

1.3.1.2 API Testing ¶

cc_flaskapi_activation.png

cc_flaskapi_documentation.png

cc_flaskapi_endpoints.png

In [33]:
##################################
# Loading Python Libraries
##################################
import requests
In [34]:
##################################
# Defining the base URL of the API
# for the categorical classification model
##################################
CC_FLASKAPI_BASE_URL = "http://127.0.0.1:5000/"
In [35]:
##################################
# Defining the input values for an individual test case
##################################
individual_test_case = {
    "features_individual": [1, 0, 0, 0, 0, 1, 0, 0, 1, 1] 
}
In [36]:
##################################
# Defining the input values for a batch of cases
##################################
batch_test_case = {
    "features_list": [
        [1, 0, 0, 0, 0, 1, 0, 0, 1, 1], 
        [1, 0, 1, 0, 1, 1, 0, 1, 1, 1]
    ]
}
In [37]:
##################################
# Generating a GET endpoint request for
# validating API service connection
##################################
response = requests.get(f"{CC_FLASKAPI_BASE_URL}/")
if response.status_code == 200:
    print("Root Endpoint Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Root Endpoint Response: {'message': 'Welcome to the Categorical Classification API!'}
In [38]:
##################################
# Generating a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{CC_FLASKAPI_BASE_URL}/predict-individual-logit-probability-class", json=individual_test_case)
if response.status_code == 200:
    print("Individual Test Case Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Individual Test Case Response: {'logit': -1.2117837409390746, 'probability': 0.22938559072691203, 'risk_class': 'Low-Risk'}
In [39]:
##################################
# Sending a POST endpoint request for
# computing the risk index,
# estimating the lung cancer probability,
# and predicting the risk category
# of a list of train cases
##################################
response = requests.post(f"{CC_FLASKAPI_BASE_URL}/predict-list-logit-probability-class", json=batch_test_case)
if response.status_code == 200:
    print("Batch Test Case Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Batch Test Case Response: {'logit': [-1.2117837409390746, 3.4784950973590973], 'logit_sorted': [-1.2117837409390746, 3.4784950973590973], 'probability': [0.22938559072691203, 0.9700696569701589], 'probability_sorted': [0.22938559072691203, 0.9700696569701589]}
In [40]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [1, 0, 1]}
response = requests.post(f"{CC_FLASKAPI_BASE_URL}/predict-individual-logit-probability-class", json=malformed_test_case)
if response.status_code == 200:
    print("Malformed Test Case Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Error: 400 {"error":"'features_individual'"}

1.3.2 Survival Prediction ¶

1.3.2.1 API Building ¶

sp_flaskapi_code.png

1.3.2.2 API Testing ¶

sp_flaskapi_activation.png

sp_flaskapi_documentation.png

sp_flaskapi_endpoints.png

In [41]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import pandas as pd
import base64
from IPython.display import Image, display
In [42]:
##################################
# Defining the base URL of the API
# for the survival prediction model
##################################
SP_FLASKAPI_BASE_URL = "http://127.0.0.1:5001"
In [43]:
##################################
# Defining the input values for an individual test case
##################################
single_test_case = {
    "features_individual": [43, 0, 75, 1, 0.75, 100]  
}
In [44]:
##################################
# Defining the input values for a batch of cases
##################################
train_list = {
    "features_list": [
        [43, 0, 75, 1, 0.75, 100],
        [70, 1, 20, 1, 0.75, 100]
    ]
}
In [45]:
##################################
# Defining the input values for a batch of cases for binning request
##################################
bin_request = {
    "X_original_list": [
        {"AGE": -0.10, "EJECTION_FRACTION": -0.10, "SERUM_CREATININE": -0.10, "SERUM_SODIUM": -0.10},
        {"AGE": 0.20, "EJECTION_FRACTION": 0.20, "SERUM_CREATININE": 0.20, "SERUM_SODIUM": 0.20},
        {"AGE": 0.90, "EJECTION_FRACTION": 0.90, "SERUM_CREATININE": 0.90, "SERUM_SODIUM": 0.90}
    ],
    "numeric_feature": "AGE"
}
In [46]:
##################################
# Defining the input values for a batch of cases for Kaplan-Meier plotting
##################################
km_request = {
    "df": [
        {"TIME": 0, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 25, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 50, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 100, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 125, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 150, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 175, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 200, "DEATH_EVENT": 0, "AGE": "Low"},
        {"TIME": 225, "DEATH_EVENT": 1, "AGE": "Low"},
        {"TIME": 250, "DEATH_EVENT": 1, "AGE": "Low"},
        {"TIME": 0, "DEATH_EVENT": 0, "AGE": "High"},
        {"TIME": 25, "DEATH_EVENT": 0, "AGE": "High"},
        {"TIME": 50, "DEATH_EVENT": 0, "AGE": "High"},
        {"TIME": 100, "DEATH_EVENT": 1, "AGE": "High"},
        {"TIME": 125, "DEATH_EVENT": 0, "AGE": "High"},
        {"TIME": 150, "DEATH_EVENT": 0, "AGE": "High"},
        {"TIME": 175, "DEATH_EVENT": 1, "AGE": "High"},
        {"TIME": 200, "DEATH_EVENT": 1, "AGE": "High"},
        {"TIME": 225, "DEATH_EVENT": 1, "AGE": "High"},
        {"TIME": 250, "DEATH_EVENT": 1, "AGE": "High"},
    ],
    "cat_var": "AGE",
    "new_case_value": "Low"
}
In [47]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{SP_FLASKAPI_BASE_URL}/")
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'message': 'Welcome to the Survival Prediction API!'}
In [48]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile,
# estimating the heart failure survival probabilities,
# and predicting the risk category
# of an individual test case
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/compute-individual-coxph-survival-probability-class/", json=single_test_case)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'risk_category': 'Low-Risk',
 'survival_function': [0.9973812917524568,
  0.9920416812438736,
  0.9893236791425079,
  0.972381113071464,
  0.9693179903073035,
  0.9631930672135339,
  0.9631930672135339,
  0.9600469571766689,
  0.9600469571766689,
  0.9568596864927983,
  0.9536305709158891,
  0.9471625843882805,
  0.93729581350105,
  0.9338986486591409,
  0.93048646553474,
  0.9270645831787163,
  0.9202445006124622,
  0.9167715111530355,
  0.9132845175345189,
  0.9097550958520674,
  0.9097550958520674,
  0.9097550958520674,
  0.9060810720432387,
  0.9024157452999795,
  0.9024157452999795,
  0.9024157452999795,
  0.9024157452999795,
  0.9024157452999795,
  0.8985598696587259,
  0.8985598696587259,
  0.8985598696587259,
  0.8945287485160898,
  0.8945287485160898,
  0.8945287485160898,
  0.8945287485160898,
  0.8901959645503091,
  0.8812352215018253,
  0.8812352215018253,
  0.8812352215018253,
  0.8812352215018253,
  0.8764677174183527,
  0.8764677174183527,
  0.8764677174183527,
  0.8764677174183527,
  0.8709113650481243,
  0.8709113650481243,
  0.8652494086650531,
  0.8593884303802698,
  0.8593884303802698,
  0.8593884303802698,
  0.8593884303802698,
  0.8593884303802698,
  0.8528574859874233,
  0.8528574859874233,
  0.8528574859874233,
  0.8528574859874233,
  0.8528574859874233,
  0.8459534502216807,
  0.8389821875092403,
  0.8319419786276306,
  0.8246669811915435,
  0.8099879066057215,
  0.8099879066057215,
  0.7943979200335176,
  0.7943979200335176,
  0.7943979200335176,
  0.7943979200335176,
  0.7943979200335176,
  0.7848178617845467,
  0.7848178617845467,
  0.7848178617845467,
  0.7848178617845467,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7741993572193384,
  0.7555469848652164,
  0.7555469848652164,
  0.7555469848652164,
  0.7555469848652164,
  0.7555469848652164,
  0.7337716342207724,
  0.7337716342207724,
  0.7337716342207724,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696,
  0.7070184115456696],
 'survival_probabilities': [90.97550958520674,
  87.64677174183527,
  84.59534502216806,
  78.48178617845467,
  70.70184115456696],
 'survival_time': [50, 100, 150, 200, 250]}
In [49]:
##################################
# Sending a POST endpoint request for
# generating the heart failure survival profile and
# estimating the heart failure survival probabilities
# of a list of train cases
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/compute-list-coxph-survival-profile/", json=train_list)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
{'survival_profiles': [[0.9973812917524568,
   0.9920416812438736,
   0.9893236791425079,
   0.972381113071464,
   0.9693179903073035,
   0.9631930672135339,
   0.9631930672135339,
   0.9600469571766689,
   0.9600469571766689,
   0.9568596864927983,
   0.9536305709158891,
   0.9471625843882805,
   0.93729581350105,
   0.9338986486591409,
   0.93048646553474,
   0.9270645831787163,
   0.9202445006124622,
   0.9167715111530355,
   0.9132845175345189,
   0.9097550958520674,
   0.9097550958520674,
   0.9097550958520674,
   0.9060810720432387,
   0.9024157452999795,
   0.9024157452999795,
   0.9024157452999795,
   0.9024157452999795,
   0.9024157452999795,
   0.8985598696587259,
   0.8985598696587259,
   0.8985598696587259,
   0.8945287485160898,
   0.8945287485160898,
   0.8945287485160898,
   0.8945287485160898,
   0.8901959645503091,
   0.8812352215018253,
   0.8812352215018253,
   0.8812352215018253,
   0.8812352215018253,
   0.8764677174183526,
   0.8764677174183526,
   0.8764677174183526,
   0.8764677174183526,
   0.8709113650481243,
   0.8709113650481243,
   0.8652494086650531,
   0.8593884303802697,
   0.8593884303802697,
   0.8593884303802697,
   0.8593884303802697,
   0.8593884303802697,
   0.8528574859874233,
   0.8528574859874233,
   0.8528574859874233,
   0.8528574859874233,
   0.8528574859874233,
   0.8459534502216807,
   0.8389821875092403,
   0.8319419786276306,
   0.8246669811915435,
   0.8099879066057215,
   0.8099879066057215,
   0.7943979200335176,
   0.7943979200335176,
   0.7943979200335176,
   0.7943979200335176,
   0.7943979200335176,
   0.7848178617845467,
   0.7848178617845467,
   0.7848178617845467,
   0.7848178617845467,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7741993572193384,
   0.7555469848652164,
   0.7555469848652164,
   0.7555469848652164,
   0.7555469848652164,
   0.7555469848652164,
   0.7337716342207724,
   0.7337716342207724,
   0.7337716342207724,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695,
   0.7070184115456695],
  [0.9761144218801228,
   0.928980888267716,
   0.905777064852962,
   0.7724242339590301,
   0.7502787164583535,
   0.7076872741961866,
   0.7076872741961866,
   0.6866593185026403,
   0.6866593185026403,
   0.6659260634219393,
   0.6454915885099762,
   0.6062342264686207,
   0.5504405490863784,
   0.5323184765768243,
   0.5146536440658629,
   0.49746533888245986,
   0.464726413395405,
   0.4488047347163327,
   0.433309930422515,
   0.4181140392975694,
   0.4181140392975694,
   0.4181140392975694,
   0.4028020116306455,
   0.38802639234746467,
   0.38802639234746467,
   0.38802639234746467,
   0.38802639234746467,
   0.38802639234746467,
   0.373006008573048,
   0.373006008573048,
   0.373006008573048,
   0.35785929480690143,
   0.35785929480690143,
   0.35785929480690143,
   0.35785929480690143,
   0.3421927616040032,
   0.3117176431598899,
   0.3117176431598899,
   0.3117176431598899,
   0.3117176431598899,
   0.29651072362871467,
   0.29651072362871467,
   0.29651072362871467,
   0.29651072362871467,
   0.2796248763802668,
   0.2796248763802668,
   0.2633052706162029,
   0.24731169874453887,
   0.24731169874453887,
   0.24731169874453887,
   0.24731169874453887,
   0.24731169874453887,
   0.23051507888001282,
   0.23051507888001282,
   0.23051507888001282,
   0.23051507888001282,
   0.23051507888001282,
   0.213871875082776,
   0.19816204676152543,
   0.18334919195124752,
   0.16908728217620728,
   0.1432835564355214,
   0.1432835564355214,
   0.119778195679268,
   0.119778195679268,
   0.119778195679268,
   0.119778195679268,
   0.119778195679268,
   0.10710184631976834,
   0.10710184631976834,
   0.10710184631976834,
   0.10710184631976834,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.09446095671842468,
   0.07544024472233593,
   0.07544024472233593,
   0.07544024472233593,
   0.07544024472233593,
   0.07544024472233593,
   0.05761125190131533,
   0.05761125190131533,
   0.05761125190131533,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404,
   0.040906392932898404]]}
In [50]:
##################################
# Sending a POST endpoint request for
# creating dichotomous bins for the numeric features
# of a list of train cases
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/bin-numeric-model-feature/", json=bin_request)
if response.status_code == 200:
    display("Response:", pd.DataFrame(response.json()))
else:
    print("Error:", response.status_code, response.text)
    
'Response:'
AGE EJECTION_FRACTION SERUM_CREATININE SERUM_SODIUM
0 Low -0.1 -0.1 -0.1
1 High 0.2 0.2 0.2
2 High 0.9 0.9 0.9
In [51]:
##################################
# Sending a POST endpoint request for
# plotting the estimated survival profiles
# using Kaplan-Meier Plots
##################################
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/plot-kaplan-meier/", json=km_request)
if response.status_code == 200:
    plot_data = response.json()["plot"]
    # Decoding and displaying the plot
    img = base64.b64decode(plot_data)
    with open("kaplan_meier_plot.png", "wb") as f:
        f.write(img)
        display(Image("kaplan_meier_plot.png"))
else:
    print("Error:", response.status_code, response.text)
    
No description has been provided for this image
In [52]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_test_case = {"features": [43, 0, 75, 1, 0.75]}
response = requests.post(f"{SP_FLASKAPI_BASE_URL}/compute-individual-coxph-survival-probability-class/", json=malformed_test_case)
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
    
Error: 400 {"error":"Missing 'features_individual' in request"}

1.3.3 Image Classification ¶

1.3.3.1 API Building ¶

ic_flaskapi_code.png

1.3.3.2 API Testing ¶

ic_flaskapi_activation.png

ic_flaskapi_documentation.png

ic_flaskapi_endpoints.png

In [53]:
##################################
# Loading Python Libraries
##################################
import requests
import json
import base64
from IPython.display import display
from PIL import Image
import matplotlib.pyplot as plt
import io
from tensorflow.keras.utils import load_img
import os
import mimetypes
In [54]:
##################################
# Defining the base URL of the API
# for the image classification model
##################################
IC_FLASKAPI_BASE_URL = "http://127.0.0.1:5002"
In [55]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
image_path = (os.path.join("..",IMAGES_PATH, "test_image.jpg"))
In [56]:
##################################
# Automatically determining the filename and content type
##################################
image_path_filename = os.path.basename(image_path)
image_path_content_type, _ = mimetypes.guess_type(image_path)
In [57]:
##################################
# Visualizing the individual test image
##################################
try:
    image = Image.open(image_path)
    print(f"Image File Path: {image_path}")
    print(f"Image Format: {image.format}")
    print(f"Image Size: {image.size}")
    print(f"Image Mode: {image.mode}") 
except Exception as e:
    print(f"Error loading image: {e}")
plt.imshow(image)
plt.axis('off') 
plt.title("Test Image")
plt.show()
Image File Path: ..\image_classification_study\images\test_image.jpg
Image Format: JPEG
Image Size: (215, 234)
Image Mode: RGB
No description has been provided for this image
In [58]:
##################################
# Generating a GET endpoint request for
# for validating API service connection
##################################
response = requests.get(f"{IC_FLASKAPI_BASE_URL}/")
if response.status_code == 200:
    display("Response:", response.json())
else:
    print("Error:", response.status_code, response.text)
'Response:'
{'message': 'Welcome to the Image Classification API!'}
In [59]:
##################################
# Sending a POST endpoint request for
# ensuring that the file upload mechanism is working
# by returning the the file metadata
##################################
with open(image_path, "rb") as file:
    files = {"file": (image_path_filename, file, image_path_content_type)}
    response = requests.post(f"{IC_FLASKAPI_BASE_URL}/test-file-upload/", files=files)

    if response.status_code == 200:
        result = response.json()
        print("File Upload Test Result:")
        print(f"Filename: {result['filename']}")
        print(f"Content Type: {result['content_type']}")
        print(f"Size: {result['size']} bytes")
    else:
        print(f"Error: {response.status_code} - {response.text}")
File Upload Test Result:
Filename: test_image.jpg
Content Type: image/jpeg
Size: 12103 bytes
In [60]:
##################################
# Sending a POST endpoint request for
# predicting the image category and
# estimating class probabilities
# of an individual test image
##################################
with open(image_path, "rb") as file:
    files = {"file": ("image.jpg", file, "image/jpeg")}
    response = requests.post(f"{IC_FLASKAPI_BASE_URL}/predict-image-category-class-probability/", files=files)
    
    if response.status_code == 200:
        result = response.json()
        print("Prediction Result:")
        print(f"Predicted Class: {result['predicted_class']}")
        print("Probabilities:")
        for cls, prob in result["probabilities"].items():
            print(f"{cls}: {prob:.5f}%")
    else:
        print(f"Error: {response.status_code} - {response.text}")
Prediction Result:
Predicted Class: Meningioma
Probabilities:
Glioma: 0.02788%
Meningioma: 87.02222%
No Tumor: 12.94989%
Pituitary: 0.00002%
In [61]:
##################################
# Sending a POST endpoint request for
# formulating the gradient class activation map
# from the output of the first to third convolutional layers and
# and superimposing on the actual image
##################################
with open(image_path, "rb") as file:
    files = {"file": ("image.jpg", file, "image/jpeg")}
    response = requests.post(f"{IC_FLASKAPI_BASE_URL}/visualize-image-gradcam/", files=files)
    
    if response.status_code == 200:
        plot_data = response.json()["plot"]
        # Decoding and displaying the plot
        img = base64.b64decode(plot_data)
        with open("image_gradcam_plot.png", "wb") as f:
            f.write(img)
            display(Image.open("image_gradcam_plot.png"))
    else:
        print(f"Error: {response.status_code} - {response.text}")
No description has been provided for this image
In [62]:
##################################
# Defining the file path for an individual test image
##################################
IMAGES_PATH = r"image_classification_study\images"
malformed_image_path = (os.path.join("..",IMAGES_PATH, "test_image.png"))
In [63]:
##################################
# Automatically determining the filename and content type
##################################
malformed_image_path_filename = os.path.basename(image_path)
malformed_image_path_content_type, _ = mimetypes.guess_type(malformed_image_path)
In [64]:
##################################
# Sending a POST endpoint request
# using malformed data to evaluate
# the API's error handling function
##################################
malformed_image_path = (os.path.join("..",IMAGES_PATH, "test_image.png"))
with open(malformed_image_path, "rb") as file:
    files = {"file": (malformed_image_path_filename, file, malformed_image_path_content_type)}
    response = requests.post(f"{IC_FLASKAPI_BASE_URL}/test-file-upload/", files=files)

    if response.status_code == 200:
        result = response.json()
        print("File Upload Test Result:")
        print(f"Filename: {result['filename']}")
        print(f"Content Type: {result['content_type']}")
        print(f"Size: {result['size']} bytes")
    else:
        print(f"Error: {response.status_code} - {response.text}")
        
Error: 400 - {"error":"File must be a JPEG image"}

1.4. Consolidated Findings ¶

2. Summary ¶

3. References ¶

  • [Book] Designing Machine Learning Systems: An Iterative Process for Production-Ready Applications by Chip Huyen
  • [Book] Machine Learning Bookcamp: Build a Portfolio of Real-Life Projects by Alexey Grigorev and Adam Newmark
  • [Book] Building Machine Learning Pipelines: Automating Model Life Cycles with TensorFlow by Hannes Hapke and Catherine Nelson
  • [Book] Hands-On APIs for AI and Data Science: Python Development with FastAPI by Ryan Day
  • [Book] Managing Machine Learning Projects: From Design to Deployment by Simon Thompson
  • [Book] Building Data Science Applications with FastAPI: Develop, Manage, and Deploy Efficient Machine Learning Applications with Python by François Voron
  • [Book] Microservice APIs: Using Python, Flask, FastAPI, OpenAPI and More by Jose Haro Peralta
  • [Book] Machine Learning Engineering with Python: Manage the Lifecycle of Machine Learning odels using MLOps with Practical Examples by Andrew McMahon
  • [Book] Introducing MLOps: How to Scale Machine Learning in the Enterprise by Mark Treveil, Nicolas Omont, Clément Stenac, Kenji Lefevre, Du Phan, Joachim Zentici, Adrien Lavoillotte, Makoto Miyazaki and Lynn Heidmann
  • [Book] Practical Python Backend Programming: Build Flask and FastAPI Applications, Asynchronous Programming, Containerization and Deploy Apps on Cloud by Tim Peters
  • [Python Library API] NumPy by NumPy Team
  • [Python Library API] pandas by Pandas Team
  • [Python Library API] seaborn by Seaborn Team
  • [Python Library API] matplotlib.pyplot by MatPlotLib Team
  • [Python Library API] matplotlib.image by MatPlotLib Team
  • [Python Library API] matplotlib.offsetbox by MatPlotLib Team
  • [Python Library API] itertools by Python Team
  • [Python Library API] operator by Python Team
  • [Python Library API] sklearn.experimental by Scikit-Learn Team
  • [Python Library API] sklearn.impute by Scikit-Learn Team
  • [Python Library API] sklearn.linear_model by Scikit-Learn Team
  • [Python Library API] sklearn.preprocessing by Scikit-Learn Team
  • [Python Library API] scipy by SciPy Team
  • [Python Library API] sklearn.tree by Scikit-Learn Team
  • [Python Library API] sklearn.ensemble by Scikit-Learn Team
  • [Python Library API] sklearn.svm by Scikit-Learn Team
  • [Python Library API] sklearn.metrics by Scikit-Learn Team
  • [Python Library API] sklearn.model_selection by Scikit-Learn Team
  • [Python Library API] imblearn.over_sampling by Imbalanced-Learn Team
  • [Python Library API] imblearn.under_sampling by Imbalanced-Learn Team
  • [Python Library API] SciKit-Survival by SciKit-Survival Team
  • [Python Library API] SciKit-Learn by SciKit-Learn Team
  • [Python Library API] StatsModels by StatsModels Team
  • [Python Library API] SciPy by SciPy Team
  • [Python Library API] Lifelines by Lifelines Team
  • [Python Library API] tensorflow by TensorFlow Team
  • [Python Library API] keras by Keras Team
  • [Python Library API] pil by Pillow Team
  • [Python Library API] glob by glob Team
  • [Python Library API] cv2 by OpenCV Team
  • [Python Library API] os by os Team
  • [Python Library API] random by random Team
  • [Python Library API] keras.models by TensorFlow Team
  • [Python Library API] keras.layers by TensorFlow Team
  • [Python Library API] keras.wrappers by TensorFlow Team
  • [Python Library API] keras.utils by TensorFlow Team
  • [Python Library API] keras.optimizers by TensorFlow Team
  • [Python Library API] keras.preprocessing.image by TensorFlow Team
  • [Python Library API] keras.callbacks by TensorFlow Team
  • [Python Library API] keras.metrics by TensorFlow Team
  • [Python Library API] sklearn.metrics by Scikit-Learn Team
  • [Python Library API] Streamlit by Streamlit Team
  • [Python Library API] Streamlit Community Cloud by Streamlit Team
  • [Article] ML - Deploy Machine Learning Models Using FastAPI by Dorian Machado (Medium)
  • [Article] Deploying Machine Learning Models Using FastAPI by Kevin Njagi (Medium)
  • [Article] Deploy Machine Learning API with FastAPI for Free by Aniket Maurya (Lightning.AI)
  • [Article] How to Use FastAPI for Machine Learning by Cheuk Ting Ho (JetBrains.Com)
  • [Article] Deploying and Hosting a Machine Learning Model with FastAPI and Heroku by Michael Herman (TestDriven.IO)
  • [Article] A Practical Guide to Deploying Machine Learning Models by Bala Priya (MachineLearningMastery.Com)
  • [Article] Using FastAPI to Deploy Machine Learning Models by Carl Handlin (Medium)
  • [Article] How to Deploy a Machine Learning Model by Maarten Grootendorst (MaartenGrootendorst.Com)
  • [Article] Accelerating Machine Learning Deployment: Unleashing the Power of FastAPI and Docker by Pratyush Khare (Medium)
  • [Article] Containerize and Deploy ML Models with FastAPI & Docker by Hemachandran Dhinakaran (Medium)
  • [Article] Quick Tutorial to Deploy Your ML models using FastAPI and Docker by Shreyansh Singh (GitHub)
  • [Article] How to Deploying Machine Learning Models in Production by Umair Akram (Medium)
  • [Article] Deploying a Machine Learning Model with FastAPI: A Comprehensive Guide by Muhammad Naveed Arshad (Medium)
  • [Article] Deploy Machine Learning Model with REST API using FastAPI by Yusuf Berki Yazıcıoğlu (Medium)
  • [Article] Deploying An ML Model With FastAPI — A Succinct Guide by Yash Prakash (Medium)
  • [Article] How to Build a Machine Learning App with FastAPI: Dockerize and Deploy the FastAPI Application to Kubernetes by Bravin Wasike (Dev.TO)
  • [Article] Building a Machine Learning Model API with Flask: A Step-by-Step Guide by Nilesh Shinde (Medium)
  • [Article] Deploying Your Machine Learning Model as a REST API Using Flask by Emmanuel Oludare (Medium)
  • [Article] Machine Learning Model Deployment on Heroku Using Flask by Charu Makhijani (Medium)
  • [Article] Model Deployment using Flask by Ravindra Sharma (Medium)
  • [Article] Deploy a Machine Learning Model using Flask: Step-By-Step by Claudio Sabato (CodeFather.Tech)
  • [Article] How to Deploy a Machine Learning Model using Flask? by DataDance.AI Team (DataDance.AI)
  • [Article] A Comprehensive Guide on Deploying Machine Learning Models with Flask by MachineLearningModels.Org Team (MachineLearningModels.Org)
  • [Article] How to Deploy Machine Learning Models with Flask and Docker by Usama Malik (Medium)
  • [Article] Deploying Machine Learning Models with Flask: A Step-by-Step Guide by Sukma Hanifa (Medium)
  • [Article] Machine Learning Model Deployment on Heroku Using Flask by Charu Makhijani (Medium)
  • [Article] Complete Guide on Model Deployment with Flask and Heroku by Tarek Ghanoum (Medium)
  • [Article] Turning Machine Learning Models into APIs in Python by Sayak Paul (DataCamp)
  • [Article] Machine Learning, Pipelines, Deployment and MLOps Tutorial by Moez Ali (DataCamp)
  • [Video Tutorial] Machine Learning Models Deployment with Flask and Docker by Data Science Dojo (YouTube)
  • [Video Tutorial] Deploy Machine Learning Model Flask by Stats Wire (YouTube)
  • [Video Tutorial] Deploy Machine Learning Models with Flask | Using Render to host API and Get URL :Step-By-Step Guide by Prachet Shah (YouTube)
  • [Video Tutorial] Deploy Machine Learning Model using Flask by Krish Naik (YouTube)
  • [Video Tutorial] Deploy Your ML Model Using Flask Framework by MSFTImagine (YouTube)
  • [Video Tutorial] Build a Machine Learning App From Scratch with Flask & Docker by Patrick Loeber (YouTube)
  • [Video Tutorial] Deploying a Machine Learning Model to a Web with Flask and Python Anywhere by Prof. Phd. Manoel Gadi (YouTube)
  • [Video Tutorial] End To End Machine Learning Project With Deployment Using Flask by Data Science Diaries (YouTube)
  • [Video Tutorial] Publish ML Model as API or Web with Python Flask by Python ML Daily (YouTube)
  • [Video Tutorial] Deploy a Machine Learning Model using Flask API to Heroku by Jackson Yuan (YouTube)
  • [Video Tutorial] Deploying Machine Learning Model with FlaskAPI - CI/CD for ML Series by Anthony Soronnadi (YouTube)
  • [Video Tutorial] Deploy ML model as Webservice | ML model deployment | Machine Learning | Data Magic by Data Magic (YouTube)
  • [Video Tutorial] Deploying Machine Learning Model Using Flask by DataMites (YouTube)
  • [Video Tutorial] ML Model Deployment With Flask On Heroku | How To Deploy Machine Learning Model With Flask | Edureka by Edureka (YouTube)
  • [Video Tutorial] ML Model Deployment with Flask | Machine Learning & Data Science by Dan Bochman (YouTube)
  • [Video Tutorial] How to Deploy ML Solutions with FastAPI, Docker, & AWS by Shaw Talebi (YouTube)
  • [Video Tutorial] Deploy ML models with FastAPI, Docker, and Heroku | Tutorial by AssemblyAI (YouTube)
  • [Video Tutorial] Machine Learning Model Deployment Using FastAPI by TheOyinbooke (YouTube)
  • [Video Tutorial] Creating APIs For Machine Learning Models with FastAPI by NeuralNine (YouTube)
  • [Video Tutorial] How To Deploy Machine Learning Models Using FastAPI-Deployment Of ML Models As API’s by Krish Naik (YouTube)
  • [Video Tutorial] Machine Learning Model with FastAPI, Streamlit and Docker by CodeTricks (YouTube)
  • [Video Tutorial] FastAPI Machine Learning Model Deployment | Python | FastAPI by Stats Wire (YouTube)
  • [Video Tutorial] Deploying Machine Learning Models - Full Guide by NeuralNine (YouTube)
  • [Video Tutorial] Model Deployment FAST API - Docker | Machine Learning Model Deployment pipeline | FastAPI VS Flask by 360DigiTMG (YouTube)
  • [Video Tutorial] Build an AI app with FastAPI and Docker - Coding Tutorial with Tips by Patrick Loeber (YouTube)
  • [Video Tutorial] Create a Deep Learning API with Python and FastAPI by DataQuest (YouTube)
  • [Video Tutorial] Fast API Machine Learning Web App Tutorial + Deployment on Heroku by Greg Hogg (YouTube)
  • [Course] Deeplearning.AI Machine Learning in Production by DeepLearning.AI Team (Coursera)
  • [Course] IBM AI Workflow: Enterprise Model Deployment by IBM Team (Coursera)
  • [Course] DataCamp Machine Learning Engineer Track by DataCamp Team (DataCamp)
  • [Course] DataCamp Designing Machine Learning Workflows in Python by DataCamp Team (DataCamp)
  • [Course] DataCamp Building APIs in Python by DataCamp Team (DataCamp)
In [65]:
from IPython.display import display, HTML
display(HTML("<style>.rendered_html { font-size: 15px; font-family: 'Trebuchet MS'; }</style>"))